package obsimpl

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"strings"
	"time"

	"github.com/astaxie/beego"
	"github.com/huaweicloud/huaweicloud-sdk-go-obs/obs"
)

var instance *obsImpl

var dynamicDir string

func SetDynamicDir(dir string) {
	dynamicDir = dir
}

func Init() error {
	cfg := Config{
		AccessKey:     beego.AppConfig.String("obs::access_key_id"),
		SecretKey:     beego.AppConfig.String("obs::secret_access_key"),
		Endpoint:      beego.AppConfig.String("obs::endpoint"),
		Bucket:        beego.AppConfig.String("obs::bucket"),
		Directory:     beego.AppConfig.String("obs::upload_cvrf_dir"),
		UpdateInfoDir: beego.AppConfig.String("obs::upload_updateinfo_dir"),
	}

	cli, err := obs.New(cfg.AccessKey, cfg.SecretKey, cfg.Endpoint)
	if err != nil {
		return err
	}

	instance = &obsImpl{
		cfg: &cfg,
		cli: cli,
	}

	return nil
}

func Instance() *obsImpl {
	return instance
}

type obsImpl struct {
	cfg *Config
	cli *obs.ObsClient
}

func (impl obsImpl) UploadToDynamicDir(fileName string, data []byte) error {
	input := &obs.PutObjectInput{}
	input.Bucket = impl.cfg.Bucket
	input.Key = impl.getDynamicDir() + fileName
	input.Body = bytes.NewReader(data)

	_, err := impl.cli.PutObject(input)

	return err
}

func (impl obsImpl) DownloadFromDynamicDir(fileName string) ([]byte, error) {
	input := &obs.GetObjectInput{}
	input.Bucket = impl.cfg.Bucket
	input.Key = impl.getDynamicDir() + fileName
	output, err := impl.cli.GetObject(input)
	if err != nil {
		return nil, err
	}
	defer output.Body.Close()

	return ioutil.ReadAll(output.Body)
}

func (impl obsImpl) UploadUpdateInfo(fileName string, data []byte) error {
	input := &obs.PutObjectInput{}
	input.Bucket = impl.cfg.Bucket
	nowStr := time.Now().Format("2006-01-02")
	input.Key = fmt.Sprintf("%s%s-%s/%s", impl.cfg.UpdateInfoDir, nowStr, "hotpatch", fileName)
	input.Body = bytes.NewReader(data)

	_, err := impl.cli.PutObject(input)

	return err
}

func (impl obsImpl) getDynamicDir() string {
	todayStr := time.Now().Format("2006-01-02")
	if strings.Contains(dynamicDir, todayStr) {
		return dynamicDir
	}

	return fmt.Sprintf("%s%s-%s/", impl.cfg.UpdateInfoDir, todayStr, "hotpatch")
}

func (impl obsImpl) Upload(path string, data []byte) error {
	input := &obs.PutObjectInput{}
	input.Bucket = impl.cfg.Bucket
	input.Key = path
	input.Body = bytes.NewReader(data)

	_, err := impl.cli.PutObject(input)

	return err
}

func (impl obsImpl) Download(path string) ([]byte, error) {
	input := &obs.GetObjectInput{}
	input.Bucket = impl.cfg.Bucket
	input.Key = path
	output, err := impl.cli.GetObject(input)
	if err != nil {
		return nil, err
	}
	defer output.Body.Close()

	return io.ReadAll(output.Body)
}
